﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ApiGateway.Auth.Dto;
using Gmmy.ApplicationExtension;
using Gmmy.Utility;
using Gmmy.Utility.Enums;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Surging.Core.ApiGateWay.OAuth;
using Surging.Core.Caching;
using Surging.Core.CPlatform.Cache;
using Surging.Core.CPlatform.Ioc;
using Surging.Core.CPlatform.Routing;
using Surging.Core.ProxyGenerator;

namespace ApiGateway.Auth.Services
{
    public class AuthService: ProxyBaseService, IAuthService
    {

        private readonly IServiceProxyProvider _serviceProxyProvider;
        private readonly IServiceRouteProvider _serviceRouteProvider;
        private readonly ICacheProvider _cacheProvider;
        public AuthService(
            IServiceProxyProvider serviceProxyProvider,
            ILogger<AuthService> logger
            , IServiceRouteProvider serviceRouteProvider
        ) : base(logger)
        {
            _serviceProxyProvider = serviceProxyProvider;
            _serviceRouteProvider = serviceRouteProvider;
            _cacheProvider = CacheContainer.GetService<ICacheProvider>("ddlCache.Redis");
        }
        /// <summary>
        /// 授权登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> Authentication(LoginDto input)
        {
            return await Do(input, async result =>
            {
                var proxyInput = new Dictionary<string, object> { { "input", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(input)) } };
                var proxyResult =
                    await _serviceProxyProvider.Invoke<CustomApiResult>(proxyInput, "api/User/Login", "User");
                if (proxyResult.code == CustomApiResultCode.Succ)
                {
                   await CreateCacheToken(proxyResult.data, result);
                }
                else
                {
                    throw new CustomException(proxyResult.message);
                }
            });
        }
        /// <summary>
        /// 授权校验
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> AuthorizationCheck(UserCheckDto input)
        {
            return await Do(input, async result =>
            {
                var check = await CheckTokenCache(input.Token);
                if (check.isSuccess)
                {
                    var token = check.jwtToken.ToList();
                    var moduleData = (await GetAllModuleAddress(token)).Select(x => x.ToLower());
                    //若当前路由在路由集合中
                    if (moduleData.Contains(input.Path.ToLower()))
                    {
                        //若当前路由在用户权限中
                        if ((await GetUserRoleCache(token)).Actions.Select(x => x.ActionAddress.ToLower())
                            .Contains(input.Path.ToLower()))
                        {
                            result.data = Encoding.UTF8.GetString(Convert.FromBase64String(token[1]));
                        }
                        else
                        {
                            throw new CustomException(CustomApiResultCode.AuthorizationInvalid, "");
                        }
                    }
                    else
                    {
                        //路由没在集合中则通过
                        result.data = Encoding.UTF8.GetString(Convert.FromBase64String(token[1]));
                    }
                }
                else
                {
                    throw new CustomException(CustomApiResultCode.AuthenticationInvalid, "");
                }
            });
        }
        /// <summary>
        /// 获取登陆者信息(jwt)
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<(bool isSuccess, dynamic userInfo)> GetTokenInfo(string token)
        {
            var check = await CheckTokenCache(token);
            if (check.isSuccess)
            {
                return (check.isSuccess, Encoding.UTF8.GetString(Convert.FromBase64String(check.jwtToken.ToList()[1])));
            }
            else
            {
                return (false, null);
            }
        }
        /// <summary>
        /// 获取授权信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> Info(AuthToken input)
        {
            return await Do(input, async result =>
            {
                var check = await CheckTokenCache(input.Token);
                if (check.isSuccess)
                {
                    result.data = await GetUserRoleCache(check.jwtToken.ToList());
                }
                else
                {
                    throw new CustomException(CustomApiResultCode.AuthenticationInvalid, "");
                }
            });
        }
        /// <summary>
        /// 登出
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> Logout(AuthToken input)
        {
            return await Do(input, async result =>
            {
                await RemoveTokenCache(input.Token, true);
            });
        }

        /// <summary>
        /// 更新授权token
        /// </summary>
        /// <param name="input"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> UpdateToken(AuthToken input)
        {
            return await Do(input, async result =>
            {
                var check = await CheckTokenCache(input.Token);
                if (check.isSuccess)
                {
                    var outtoken = check.jwtToken;
                    var newTokenResult = new CustomApiResult();
                    await CreateCacheToken(input.UserInfo, newTokenResult);
                    if (newTokenResult.code == CustomApiResultCode.Succ)
                    {
                        _cacheProvider.Add($"discard_userinfo_{outtoken[1]}", newTokenResult.data, _tokenCacheExpire);
                        await RemoveTokenCache(input.Token, false);
                    }
                }
            });
        }

        /// <summary>
        /// 刷新授权缓存
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CustomApiResult> ReflushAuthToken(AuthToken input)
        {
            return await Do(input, async result =>
            {
                var check = await CheckTokenCache(input.Token);
                if (check.isSuccess)
                {
                    var outtoken = input.Token.Split(".");
                    //通过key获取discard缓存返回给用户
                    result.data = _cacheProvider.Get<string>($"discard_userinfo_{outtoken[1]}");
                    //删除discard缓存
                    _cacheProvider.Remove($"discard_userinfo_{outtoken[1]}"); 
                }
                else
                {
                    throw new CustomException(CustomApiResultCode.AuthenticationInvalid, "");
                }
            });
        }

        #region 通用代码
        private readonly TimeSpan _tokenCacheExpire = TimeSpan.FromDays(7);
        private readonly TimeSpan _roleCacheExpire = TimeSpan.FromMinutes(30);
        /// <summary>
        /// 创建缓存
        /// </summary>
        /// <param name="data"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public async Task CreateCacheToken(object data, CustomApiResult result)
        {
            var jwtHeader = JsonConvert.SerializeObject(
                new JWTSecureDataHeader() { TimeStamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") });
            var base64Payload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)));
            var encodedString = $"{Convert.ToBase64String(Encoding.UTF8.GetBytes(jwtHeader))}.{base64Payload}";
            var route = await _serviceRouteProvider.GetRouteByPath("api/User/Login");
            if (route != null)
            {
                var signature = EncryptHelper.GetHMACSHA256(encodedString, route.ServiceDescriptor.Token);
                var token = $"{encodedString}.{signature}";
                result.data = token;
                _cacheProvider.Add(base64Payload, token, _tokenCacheExpire);
            }
        }
        /// <summary>
        /// 检测缓存有效性
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<CheckTokenCacheDto> CheckTokenCache(string token)
        {
            var result = new CheckTokenCacheDto();
            result.isSuccess = false;
            result.jwtToken = token.Split('.');
            if (result.jwtToken.Length == 3)
            {
                result.isSuccess = await Task.FromResult(_cacheProvider.Get<string>(result.jwtToken[1]) == token);
                //如果缓存无效,则检查标记为待废弃的缓存
                if (!result.isSuccess)
                {
                    var discardToken = _cacheProvider.Get<string>($"discard_userinfo_{result.jwtToken[1]}");
                    if (!string.IsNullOrEmpty(discardToken))
                    {
                        var discardUser = JsonConvert.DeserializeObject<UpdateTokenDto>(Encoding.UTF8.GetString(Convert.FromBase64String(result.jwtToken[1])));
                        var newUser = JsonConvert.DeserializeObject<UpdateTokenDto>(Encoding.UTF8.GetString(Convert.FromBase64String(discardToken.Split(".")[1])));
                        if (newUser.ID == discardUser.ID)
                        {
                            result.isSuccess = true;
                            result.jwtToken = discardToken.Split(".");
                        }
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// 获取用户所有权限
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<List<string>> GetAllModuleAddress(List<string> token)
        {
            var inputparm = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(new
            {
                AuthInfo = Encoding.UTF8.GetString(Convert.FromBase64String(token[1])),
                Token = string.Join("", token),
                RequestInfo = ""
            }));
            return await GetTCache<List<string>>("all_roles", inputparm, _roleCacheExpire, "api/Module/GetModuleAddressAll", "Module");
        }
        /// <summary>
        /// 获取通用缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="headkey"></param>
        /// <param name="parm"></param>
        /// <param name="expressTime"></param>
        /// <param name="path"></param>
        /// <param name="serviceKey"></param>
        /// <returns></returns>
        public async Task<T> GetTCache<T>(string headkey, object parm, TimeSpan expressTime, string path, string serviceKey)
        {
            var result = _cacheProvider.Get<T>(headkey);
            if (result == null)
            {

                var proxyInput = new Dictionary<string, object> { { "input", parm } };
                var proxyResult =
                    await _serviceProxyProvider.Invoke<CustomApiResult>(proxyInput, path, serviceKey);
                if (proxyResult.code == CustomApiResultCode.Succ)
                {
                    result = JsonConvert.DeserializeObject<T>(
                        JsonConvert.SerializeObject(proxyResult.data));
                    _cacheProvider.Add(headkey, result, expressTime);
                }
                else
                {
                    throw new CustomException(proxyResult.message);
                }
            }
            return result;
        }
        /// <summary>
        /// 获取用户权限缓存
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<FullLoginInfoDto> GetUserRoleCache(List<string> token)
        {
            var inputparm = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(new
            {
                AuthInfo = Encoding.UTF8.GetString(Convert.FromBase64String(token[1])),
                Token = string.Join("", token),
                RequestInfo = ""
            }));
            return await GetTCache<FullLoginInfoDto>($"user_info_{token[1]}", inputparm, _tokenCacheExpire, "api/User/Info", "User");
        }

        /// <summary>
        /// 授权登出,移出缓存
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task RemoveTokenCache(string token, bool removeDiscard)
        {
            var check = await CheckTokenCache(token);
            if (check.isSuccess)
            {
                var outtoken = check.jwtToken;
                _cacheProvider.Remove(outtoken[1]); //删除用户缓存
                _cacheProvider.Remove($"user_info_{outtoken[1]}"); //删除用户关联信息缓存
                if (removeDiscard)
                {
                    _cacheProvider.Remove($"discard_userinfo_{outtoken[1]}"); //删除用户待废弃缓存缓存 
                }
            }
        }
        #endregion
    }
}
